package com.strawcom.charmring.bean;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.litepal.crud.DataSupport;

import android.annotation.SuppressLint;
import android.content.Context;
import android.database.Cursor;

import com.strawcom.charmring.App;
import com.strawcom.charmring.C;
import com.strawcom.charmring.util.LogUtil;
import com.strawcom.charmring.util.PreferenceUtil;

/**
 * @author WangPeng
 */
public class DailySummary extends DataSupport {
	private int id;
	/** 日期 yyyyMMdd */
	private String date;
	/** 消耗卡路里列表 每种运动方式一个 */
	private List<Calories> calories;
	/** 今日体重 [千克] */
	private float weight;
	/** 服务器同步标志 总汇同步 */
	private boolean syncflag1;
	/** 服务器同步标志 明细同步 */
	private boolean syncflag2;
	/** 目标总时间 */
	private int targetTime;
	/** 目标总能量 */
	private float targetEnergy;
	/** 运动总时间 */
	protected int exerciseTime = -1;
	/** 运动总能量 */
	protected float exerciseEnergy = -1;

	public DailySummary() {
	}

	public static DailySummary newIntance(Context context) {
		return newIntance(context, new Date());
	}

	@SuppressLint("SimpleDateFormat") public static DailySummary newIntance(Context context, Date date) {
		DailySummary dailySummary = new DailySummary();
		dailySummary.date = new SimpleDateFormat(C.exercise.record_date_pattern).format(date);
		dailySummary.weight = PreferenceUtil.readFloat(context, C.sp.exercise_record_weight);
		dailySummary.syncflag1 = false;
		dailySummary.syncflag2 = false;
		dailySummary.targetTime = PreferenceUtil.readInt(context, C.sp.exercise_target_time, C.exercise.target_settings_time_min);
		dailySummary.targetEnergy = PreferenceUtil.readInt(context, C.sp.exercise_target_energy, C.exercise.target_settings_energy_min);
		dailySummary.save();
		return dailySummary;
	}

	public static DailySummary newIntance(Context context, String date) {
		DailySummary dailySummary = new DailySummary();
		dailySummary.date = date;
		dailySummary.weight = PreferenceUtil.readFloat(context, C.sp.exercise_record_weight);
		dailySummary.syncflag1 = false;
		dailySummary.syncflag2 = false;
		dailySummary.targetTime = PreferenceUtil.readInt(context, C.sp.exercise_target_time, C.exercise.target_settings_time_min);
		dailySummary.targetEnergy = PreferenceUtil.readInt(context, C.sp.exercise_target_energy, C.exercise.target_settings_energy_min);
		dailySummary.save();
		return dailySummary;
	}

	public static DailySummary newEmptyIntance(Context context, String date) {
		DailySummary dailySummary = new DailySummary();
		dailySummary.date = date;
		dailySummary.weight = 0;
		dailySummary.syncflag1 = false;
		dailySummary.syncflag2 = false;
		dailySummary.targetTime = 0;
		dailySummary.targetEnergy = 0;
		return dailySummary;
	}

	public int queryExerciseTime() {
		Cursor cursor = DataSupport.findBySQL("select sum(duration) as sum_duration from Calories where type !=0 and dailySummary_id = " + id);
		cursor.moveToFirst();
		exerciseTime = cursor.getInt(cursor.getColumnIndex("sum_duration"));
		cursor.close();
		return exerciseTime;
	}

	public float queryExerciseEnergy() {
		Cursor cursor = DataSupport.findBySQL("select sum(calorie) as sum_energy from Calories where dailySummary_id = " + id);
		cursor.moveToFirst();
		exerciseEnergy = cursor.getFloat(cursor.getColumnIndex("sum_energy"));
		cursor.close();
		return exerciseEnergy;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getDate() {
		return date;
	}

	public void setDate(String date) {
		this.date = date;
	}
	
	public List<Calories> getOriginalCalories() {
		List<Calories> original = DataSupport.order("recordtime asc").where("dailySummary_id = ?", String.valueOf(id)).find(Calories.class);
		return original;
	}
	
	public List<Calories> getCalories() {
		return calories;
	}

	/**
	 * 当APP需要将每日运动数据显示到界面上，或者转换成每日运动汇总数据时，则需要对运动数据记录进行整理、合并，其算法为：
	 * 
	 * 1）遍历当日的运动记录，如果相邻两项运动记录之间的时间差大于等于1分钟，则在这段时间内插入运动模式
	 * 安静，这个被插入的运动记录，同样需要计算卡路里。
	 * 再次遍历插入了安静模式的运动记录，如果相邻两个运动记录的运动模式是一样的，则两运动记录合并为一个。
	 * 其中，运动距离、计步数，卡路里都为两项记录的累加；速度根据累加后的运动距离和运动时间再次计算。
	 * 
	 * 下图为计算样例，请参考：
	 * 
	 * 【图见中兴通讯股份有限公司 运动记步交互流程设计(V2).docx】
	 * 
	 * 合并计算后产生的新运动记录，可以直接显示到界面上，也可以进一步用于计算每日运动汇总。但不可以用于修改原始的运动记录数据。
	 * 
	 */
	public List<Calories> getResultCalories() {
		LogUtil.e("获取能量列表 getCalories:");
		List<Calories> original = DataSupport.order("recordtime asc").where("duration > 0 and step > -1 and dailySummary_id = ?", String.valueOf(id)).find(Calories.class);
		
//		for (Calories calories : original) {
//			LogUtil.e("["+calories.getType()+"]"+calories.getRecordTimeInfo() +"," + calories.getRecordTime() + "," +calories.getDuration());	
//		}
		
		// 第一道合并
		List<Calories> afterDeal1 = new ArrayList<Calories>();
		if (original != null) {
			final int deviation = 10;
			Calories last = null;
			for (int i = 0; i < original.size(); i++) {
				Calories curr = original.get(i);
				if (i > 0) {
					last = afterDeal1.get(afterDeal1.size() - 1);
					// 合并连续的同类型记录
					int minLastDuration = (last.getDuration() < 1 ? 1 : last.getDuration()) * 60;
//					if (curr.getType() == last.getType()
//							&& last.getRecordTime() + minLastDuration + deviation > curr.getRecordTime()) {
					if (curr.getType() == last.getType()) {
						last = Calories.mergeInstance(curr, last);
						LogUtil.e("合并同类型连续性运动数据["+curr.getType()+"]");
						continue;
					}
					// 插入安静
					else if (curr.getType() != last.getType()
							&& last.getRecordTime() + minLastDuration + deviation - curr.getRecordTime() < 0) {
						LogUtil.d("补充插入安静形运动数据");
						long startTimestamp = last.getRecordTime() + minLastDuration;
						long endTimestamp =  curr.getRecordTime() ;
						Calories quiet = Calories.newQuietInstance(startTimestamp ,  endTimestamp ,
								last.getDailySummary(), true);
						afterDeal1.add(quiet);
					}
				}
				LogUtil.i("插入运动数据["+curr.getType()+"]");
				afterDeal1.add(curr);
			}
		}

		// 第一道合并结果
		// LogUtil.e("合并结果：记录(" + afterDeal1.size() + ")条");
//		for (Calories calories : afterDeal1) {
//			LogUtil.d("["+calories.getType()+"]"+calories.getRecordTimeInfo() +"," + calories.getRecordTime() + "," +calories.getDuration());	
//		}
		// 第二道合并
		// 插入从0点算起的安静
		List<Calories> afterDeal2 = new ArrayList<Calories>();
		if (afterDeal1.size() > 0) {
			Calories first = afterDeal1.get(0);
			if (!"00:00".equals(first.getRecordTimeInfo())) {
				Calories cQuiet = Calories.newQuietInstance(first.calcTodayStartTimeStamp(),
						first.calcTodayCurrTimeStamp() , first.getDailySummary(), false);
				afterDeal2.add(cQuiet);
			}
		}

		for (int i = 0; i < afterDeal1.size(); i++) {
			Calories last = null;
			if (afterDeal2.size() > 0) {
				last = afterDeal2.get(afterDeal2.size() - 1);
			}
			Calories curr = afterDeal1.get(i);
			// 合并连续相同运动类型数据
			if (last != null && curr.getType() == last.getType()) {
				last = Calories.mergeInstance(curr, last);
				continue;
			}
			// 插入不同运动类型的数据
			afterDeal2.add(curr);
		}

		// 第二道合并结果
//		LogUtil.e("第二道合并结果：记录(" + afterDeal2.size() + ")条");
//		for (Calories calories : afterDeal2) {
//			LogUtil.i("["+calories.getType()+"]"+calories.getRecordTimeInfo() +"," + calories.getRecordTime() + "," +calories.getDuration());	
//		}
		
		// 第三道检查
		List<Calories> afterDeal3 = checkAndRepair(afterDeal2);
		
		return afterDeal3;
	}
	
	/** 第一条数据显示持续时间最终以第二条数据为准;如果有且只有一条数据则持续时长必须小于24小时 */
	private static List<Calories> checkAndRepair(List<Calories> dataList) {
		if(dataList != null && dataList.size() > 0) {
			Calories repaired = dataList.get(0);
			int repairDuration = repaired.getDuration() < 24 * 60 ? repaired.getDuration() :24 * 60 - 1;
			if(dataList.size() > 1) {
				Calories c2 = dataList.get(1);
				int c12spaingMin = 0;
				try {
					String timeInfo = c2.getRecordTimeInfo();
					String[] mT = timeInfo.split(":");
					c12spaingMin = Integer.parseInt(mT[0]) * 60 + Integer.parseInt(mT[1]);
				} catch (Exception e) {
				}
				
				repairDuration = Math.min(repairDuration, c12spaingMin);
			}
			
			repaired.setDuration(repairDuration);
			final float userWeight = PreferenceUtil.readFloat(App.i(), C.sp.weight, Calories.DEFAULT_WEIGHT);
			final int userAge = PreferenceUtil.readInt(App.i(), C.sp.user_age, Calories.DEFAULT_AGE);
			final boolean userMale = PreferenceUtil.readBoolean(App.i(), C.sp.sex, Calories.DEFAULT_MALE);
			repaired.setCalorie(Calories.calcExerciseCalories(0, userWeight, repairDuration, userAge, userMale, repaired.getType(), 0));
			repaired.setRecordTimeInfo("00:00");
			dataList.set(0, repaired);
		}
		return dataList;
	}

	public Calories getFirstCalories() {
		List<Calories> original = DataSupport.where("dailySummary_id = ?", String.valueOf(id)).find(Calories.class);
		if(original == null || original.size() == 0) {
			return null;
		}
		return original.get(original.size() - 1);
	}
	
	public void setCalories(List<Calories> calories) {
		this.calories = calories;
	}

	public float getWeight() {
		return weight;
	}

	public void setWeight(float weight) {
		this.weight = weight;
	}

	public boolean isSyncflag1() {
		return syncflag1;
	}

	public void setSyncflag1(boolean syncflag1) {
		this.syncflag1 = syncflag1;
	}

	public boolean isSyncflag2() {
		return syncflag2;
	}

	public void setSyncflag2(boolean syncflag2) {
		this.syncflag2 = syncflag2;
	}

	public int getTargetTime() {
		return targetTime;
	}

	public void setTargetTime(int targetTime) {
		this.targetTime = targetTime;
	}

	public float getTargetEnergy() {
		return targetEnergy;
	}

	public void setTargetEnergy(float targetEnergy) {
		this.targetEnergy = targetEnergy;
	}

	@Override public String toString() {
		return "DailySummary [id=" + id + ", date=" + date + ", calories.size()=" + calories.size() + ", weight=" + weight + ", syncflag1="
				+ syncflag1 + ", syncflag2=" + syncflag2 + ", targetTime=" + targetTime + ", targetEnergy=" + targetEnergy
				+ ", exerciseTime=" + exerciseTime + ", exerciseEnergy=" + exerciseEnergy + "]";
	}
}
